'''
Created on 15/05/2009

@author: eh01
'''
from yarra.datastore import dsmanager, sqlite3dao
from yarra.datastore.defaultdsodao import DefaultDSODAO
from yarra.datastore.dso import DSO
from yarra.datastore.dst import DST
from yarra.datastore.sqlite3dao import DSOSqlite3DAO
from yarra.datastore.dscache import DSCache
import datetime
import os
import unittest

DEFAULT_VERSION = 1

class DefaultDSODAOTest(unittest.TestCase):

    def get_dummy_unsaved_dso_1(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dso = DSO(created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object1/uri"
        dso.add_dsts([dst1, dst2])
        return dso
    
    def get_dummy_unsaved_dso_2(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dst3 = DST(subject="dummySubject2", predicate="dummyPredicate3", object=None, literal="789", literal_type="int", xml_string=None)
        dso = DSO(created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO"
        dso.uri = "/dummy/object2/uri"
        dso.add_dsts([dst1, dst2, dst3])
        return dso    
    
    def get_dummy_saved_dso_1(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dst3 = DST(subject="dummySubject2", predicate="dummyPredicate3", object=None, literal="789", literal_type="int", xml_string=None)
        dso = DSO(id=123, version=DEFAULT_VERSION, created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object/uri"
        dso.add_dsts([dst1, dst2, dst3])
        return dso 

    def setUp(self):
        dsmanager.initialize()

    def tearDown(self):
        os.remove(sqlite3dao.DATABASE_NAME)

    def test_save_case_1(self):
        """ Tests the dso is saved successfully """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso = self.get_dummy_unsaved_dso_1()
        dso = default_dso_dao.save([dso])[0]
        if dso and dso.id:
            assert True
        else:
            self.fail("DSO not return with generated id")    
    
    def test_find_by_id_and_version_case_1(self):
        """ Tests find by id and version """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso = self.get_dummy_unsaved_dso_1()
        # this should also place the result into the cache
        dso = default_dso_dao.save([dso])[0]
        copy_dso = default_dso_dao.find_by_id_and_version(dso.id, dso.version)
        if dso and copy_dso and dso is copy_dso:
            assert True
        else:
            self.fail('Copy DSO probably not returned from cache')
            
    def test_find_by_id_and_version_case_2(self):
        """ Tests find by id and version adds to cache """
        default_dso_dao1 = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso = self.get_dummy_unsaved_dso_1()
        dso = default_dso_dao1.save([dso])[0]
        # clear cache
        default_dso_dao1.clear_cache()
        # test that this query loads the result into the cache
        copy_dso1 = default_dso_dao1.find_by_id_and_version(dso.id, dso.version)
        copy_dso2 = default_dso_dao1.find_by_id_and_version(dso.id, dso.version)
        if dso and copy_dso1 and copy_dso2 and copy_dso1 is copy_dso2:
            assert True
        else:
            self.fail('Copy DSO probably not returned from cache')            

    def test_find_by_ids_case_1(self):
        """ Tests find by ids """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso1 = self.get_dummy_unsaved_dso_1()
        dso2 = self.get_dummy_unsaved_dso_2()
        
        # the saves should load the result into cache
        dso1_1 = default_dso_dao.save([dso1])[0]
        dso1_2 = default_dso_dao.save([dso1_1])[0]
        dso2_1 = default_dso_dao.save([dso2])[0]
        
        # this should retrieve the cached dsos
        dsos = default_dso_dao.find_by_ids([dso1_1.id, dso2_1.id])
        if dsos:
            for dso in dsos:
                if dso.id == dso1_2.id and not dso is dso1_2:
                    self.fail('Did not return the latest version')
                elif dso.id == dso2_1.id and not dso is dso2_1:
                    self.fail('Did not return the latest version')
            assert True
        else:
            self.fail('Find failed')
    
    def test_find_by_ids_case_2(self):
        """ Tests find by ids adds to cache """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso1 = self.get_dummy_unsaved_dso_1()
        dso2 = self.get_dummy_unsaved_dso_2()
        dso1_1 = default_dso_dao.save([dso1])[0]
        default_dso_dao.save([dso1_1])[0]
        dso2_1 = default_dso_dao.save([dso2])[0]
        # clear cache
        default_dso_dao.clear_cache()
        # test that this query loads the result into the cache
        dsos1 = default_dso_dao.find_by_ids([dso1_1.id, dso2_1.id])
        # this should retrieve the cached result
        dsos2 = default_dso_dao.find_by_ids([dso1_1.id, dso2_1.id])
        if dsos1 and dso2 and len(dsos1) == 2 and len(dsos1) == len(dsos2):
            for dso in dsos1:
                if not dso in dsos2:
                    self.fail('Did not return the same instance')
            assert True

    def test_find_by_URI_and_version_case_1(self):
        """ Tests find by uri and version """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso = self.get_dummy_unsaved_dso_1()
        # this should also place the result into the cache
        dso = default_dso_dao.save([dso])[0]
        copy_dso = default_dso_dao.find_by_URI_and_version(dso.uri, dso.version)
        if dso and copy_dso and dso is copy_dso:
            assert True
        else:
            self.fail('Copy DSO probably not returned from cache')

    def test_find_by_URI_and_version_case_2(self):
        """ Tests find by uri and version adds to cache """
        default_dso_dao1 = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso = self.get_dummy_unsaved_dso_1()
        dso = default_dso_dao1.save([dso])[0]
        # clear cache
        default_dso_dao1.clear_cache()
        # test that this query loads the result into the cache
        copy_dso1 = default_dso_dao1.find_by_URI_and_version(dso.uri, dso.version)
        copy_dso2 = default_dso_dao1.find_by_URI_and_version(dso.uri, dso.version)
        if dso and copy_dso1 and copy_dso2 and copy_dso1 is copy_dso2:
            assert True
        else:
            self.fail('Copy DSO probably not returned from cache')                    

    def test_find_by_URIs_case_1(self):
        """ Tests find by uris """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso1 = self.get_dummy_unsaved_dso_1()
        dso2 = self.get_dummy_unsaved_dso_2()
        
        # the saves should NOT load the result into cache
        dso1_1 = default_dso_dao.save([dso1])[0]
        dso1_2 = default_dso_dao.save([dso1_1])[0]
        dso2_1 = default_dso_dao.save([dso2])[0]
        
        # this should add the result into the cache
        dsos = default_dso_dao.find_by_URIs([dso1_1.uri, dso2_1.uri])
        if dsos and len(dsos) == 2:
            for dso in dsos:
                if dso.id == dso1_2.id:
                    assert True
                elif dso.id == dso2_1.id:
                    assert True
                else:
                    self.fail('Did not return the latest version')
            assert True
        else:
            self.fail('Find failed')

    def test_find_by_URIs_case_2(self):
        """ Tests find by uris adds to cache """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso1 = self.get_dummy_unsaved_dso_1()
        dso2 = self.get_dummy_unsaved_dso_2()
        dso1_1 = default_dso_dao.save([dso1])[0]
        default_dso_dao.save([dso1_1])[0]
        dso2_1 = default_dso_dao.save([dso2])[0]
        # this query loads the result into the cache
        dsos1 = default_dso_dao.find_by_URIs([dso1_1.uri])
        # this should retrieve the cached result
        dsos2 = default_dso_dao.find_by_URIs([dso1_1.uri, dso2_1.uri])
        if dsos1 and dso2 and len(dsos1) == 1 and len(dsos2) == 2:
            for dso in dsos1:
                if not dso in dsos2:
                    self.fail('Did not return the same instance')
            assert True
    
    def test_find_versions_case_1(self):
        """ Tests find versions """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso1 = self.get_dummy_unsaved_dso_1()
        dso1_1 = default_dso_dao.save([dso1])[0]
        default_dso_dao.save([dso1_1])[0]
        versions = default_dso_dao.find_versions(dso1_1.id)
        if versions and len(versions) == 2:
            assert True
        else:
            self.fail('Save or find failed')
            
    def test_find_versions_case_2(self):
        """ Tests find versions adds to cache """
        default_dso_dao = DefaultDSODAO(DSOSqlite3DAO(), DSCache())
        dso1 = self.get_dummy_unsaved_dso_1()
        dso1_1 = default_dso_dao.save([dso1])[0]
        default_dso_dao.save([dso1_1])[0]
        # this should load to cache
        versions1 = default_dso_dao.find_versions(dso1_1.id)
        # this should return the same list
        versions2 = default_dso_dao.find_versions(dso1_1.id)
        if versions1 and versions2 and len(versions1) == 2 and versions1 is versions2:
            assert True
        else:
            self.fail('Save or find failed')
            
if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()